import { Singleton } from "../../Singleton/Singleton";
import { TimeInfo } from "../Time/TimeInfo";

export const UshortMaxValue = 65535;
export const ByteMaxValue = 255;

export class IdStruct {
    public Time: number;    // 30bit
    public Process: number;  // 18bit
    public Value: number; // 16bit

    public ToLong(): number {
        let result = 0;
        result |= this.Value;
        result |= this.Process << 16;
        result |= this.Time << 34;
        return result;
    }

    constructor(time: number, process: number, value: number) {
        this.Process = process;
        this.Time = time;
        this.Value = value;
    }

    static Create(id: number): IdStruct {
        let result = id;
        let Value = (result & UshortMaxValue);
        result >>= 16;
        let Process = (result & IdGenerater.Mask18bit);
        result >>= 18;
        let Time = result;
        return new IdStruct(Time, Process, Value);
    }

    public ToString(): string {
        return `process: ${this.Process}, time: ${this.Time}, value: ${this.Value}`;
    }
}


export class InstanceIdStruct {
    public Time: number;   // 当年开始的tick 28bit
    public Process: number; // 18bit
    public Value: number;  // 18bit

    public ToLong(): number {
        let result = 0;
        result |= this.Value;
        result |= this.Process << 18;
        result |= this.Time << 36;
        return result;
    }

    constructor(time: number, process: number, value: number) {
        this.Time = time;
        this.Process = process;
        this.Value = value;
    }

    static Create(id: number): InstanceIdStruct {
        let result = id;
        let Value = (result & IdGenerater.Mask18bit);
        result >>= 18;
        let Process = (result & IdGenerater.Mask18bit);
        result >>= 18;
        let Time = result;
        return new InstanceIdStruct(Time, Process, Value);
    }

    static CreateWith(process: number, value: number): InstanceIdStruct {
        return new InstanceIdStruct(0, process, value);
    }

    public ToString(): string {
        return `process: ${this.Process}, value: ${this.Value} time: ${this.Time}`;
    }
}

export class UnitIdStruct {
    public Time: number;        // 30bit 34年
    public Zone: number;      // 10bit 1024个区
    public ProcessMode: number; // 8bit  Process % 256  一个区最多256个进程
    public Value: number;     // 16bit 每秒每个进程最大16K个Unit

    public ToLong(): number {
        let result = 0;
        result |= this.Value;
        result |= this.ProcessMode << 16;
        result |= this.Zone << 24;
        result |= this.Time << 34;
        return result;
    }

    constructor(zone: number, process: number, time: number, value: number) {
        this.Time = time;
        this.ProcessMode = (process % 256);
        this.Value = value;
        this.Zone = zone;
    }

    static Create(id: number): UnitIdStruct {
        let result = id;
        let Value = (result & UshortMaxValue);
        result >>= 16;
        let ProcessMode = (result & ByteMaxValue);
        result >>= 8;
        let Zone = (result & 0x03ff);
        result >>= 10;
        let Time = result;
        return new UnitIdStruct(Zone, ProcessMode, Time, Value);
    }

    public ToString(): string {
        return `ProcessMode: ${this.ProcessMode}, value: ${this.Value} time: ${this.Time}`;
    }

    public static GetUnitZone(unitId: number): number {
        let v = ((unitId >> 24) & 0x03ff); // 取出10bit
        return v;
    }
}

export class IdGenerater extends Singleton<IdGenerater> {

    private static _Instance: IdGenerater;
    static get Instance() {
        return this._Instance;
    }

    protected set Instance(value: IdGenerater) {
        IdGenerater._Instance = value;
    }

    public static readonly Mask18bit = 0x03ffff;

    public static readonly MaxZone = 1024;

    private static _id: number = 1;
    private static _instanceId: number = 1000000;

    private epoch2020: number;
    private value: number;
    private lastIdTime: number;

    private epochThisYear: number;
    private instanceIdValue: number;
    private lastInstanceIdTime: number;

    private unitIdValue: number = 0;
    private lastUnitIdTime: number = 0;

    constructor() {
        super();

        let epoch1970tick = new Date().getTime();
        this.epoch2020 = (new Date(2020, 1, 1, 0, 0, 0).getTime() - epoch1970tick) / 1;
        this.epochThisYear = new Date(new Date().getFullYear(), 1, 1, 0, 0, 0).getTime() / 1 - epoch1970tick;

        this.lastInstanceIdTime = this.TimeSinceThisYear();
        this.lastUnitIdTime = this.TimeSince2020();
    }

    private TimeSince2020(): number {
        let a = ((TimeInfo.Instance.FrameTime - this.epoch2020) / 1);
        return a;
    }

    private TimeSinceThisYear() {
        let a = ((TimeInfo.Instance.FrameTime - this.epochThisYear) / 1);
        return a;
    }

    GenerateInstanceId() {
        return IdGenerater._instanceId++;
    }

    GenerateId() {
        return IdGenerater._id++;
    }

    Dispose(): void {

    }

}